#include "DataSet.h"

/*
 *--------------------------------------------------------------------------------------
 *       Class:  DataSet
 *      Method:  DataSet
 * Description:  Contrói um DataSet vazio
 *--------------------------------------------------------------------------------------
 */
DataSet::DataSet(uint nInVars, uint nOutVars)
{
    this->nInVars = nInVars;
    this->nOutVars = nOutVars;
    this->filetype = INPUT;
    this->time = 0;
    this->nIterations = 1;
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  DataSet
 *      Method:  DataSet
 * Description:  Carrega o conjunto de entradas/saídas de um arquivo
 *--------------------------------------------------------------------------------------
 */
DataSet::DataSet(const char *file, int filetype)
{
    this->filetype = filetype;

    CSVFilePtr csv(new CSVFile(file, CSV_IN));

    csv->read(nInVars, nOutVars);

    // Caso seja um arquivo de saída, carrega-se também a taxa de sucesso e o tempo
    if(filetype == OUTPUT)
    {
        csv->read(successRate);
        csv->read(nIterations);
        csv->read(time);
    }
    else
    {
        this->time = 0;
        this->nIterations = 1;
    }

    while(csv->has())
    {
        DataPtr data(new Data(nInVars, nOutVars, filetype, csv));
        dataSet.push_back(data);
    }

    for(uint i = 0; i < dataSet.size(); i++)
        random.push_back(i);

    print();
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  DataSet
 *      Method:  randomize
 * Description:  Randomiza
 *--------------------------------------------------------------------------------------
 */
void DataSet::randomize()
{
    for(uint i = 0; i < random.size(); i++)
    {
        uint j = rand() % random.size();

        uint aux = random[i];
        random[i] = random[j];
        random[j] = aux;
    }
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  DataSet
 *      Method:  hasSucceeded
 * Description:  Verifica se o cálculo da rede neural foi bem sucedido para todas
 *               entradas/saídas
 *--------------------------------------------------------------------------------------
 */
bool DataSet::hasSucceeded(double tolerance)
{
    for(uint i = 0; i < dataSet.size(); i++)
        if(!dataSet[i]->hasSucceeded(tolerance))
            return false;
    return true;
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  DataSet
 *      Method:  calcSuccessRate
 * Description:  Calcula a taxa de sucesso
 *--------------------------------------------------------------------------------------
 */
void DataSet::calcSuccessRate(double tolerance)
{
    uint count = 0;

    for(uint i = 0; i < dataSet.size(); i++)
        if(dataSet[i]->hasSucceeded(tolerance))
            count++;

    successRate = count / (double) dataSet.size();
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  DataSet
 *      Method:  saveToFile
 * Description:  Salva as entradas/saídas em um arquivo
 *--------------------------------------------------------------------------------------
 */
void DataSet::saveToFile(const char *file)
{
    CSVFilePtr csv(new CSVFile(file, CSV_OUT));

    csv->write(nInVars, nOutVars);
    csv->write(successRate);
    csv->write(nIterations);
    csv->write(time);

    for(uint i = 0; i < dataSet.size(); i++)
    {
        csv->writeV(*(dataSet[i]->getInput()));
        csv->writeV(*(dataSet[i]->getOutput()));
        csv->writeV(*(dataSet[i]->getNeuralOutput()), true);
    }
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  DataSet
 *      Method:  print
 * Description:  Imprime informações na tela
 *--------------------------------------------------------------------------------------
 */
void DataSet::print(bool printNeuralOutput)
{
    cout << "#=| Input/Output Set |=================================#" << endl << endl;

    cout << "Number of input variables: " << nInVars << endl;
    cout << "Number of output variables: " << nOutVars << endl;

    if(printNeuralOutput || filetype == OUTPUT)
    {
        cout << "Success Rate: " << successRate << endl;
        cout << "Number of iterations: " << nIterations << " iterations" << endl;
        cout << "Total training/test time: " << time << " ms" << endl;
    }
    cout << endl;

    for(uint i = 0; i < dataSet.size(); i++)
    {
        cout << "Input/Ouput " << (i + 1) << endl;

        cout << " |--> Input:  ";
        dataSet[i]->printInput();
        cout << endl;

        cout << " |--> Output: ";
        dataSet[i]->printOutput();
        cout << endl;

        if(printNeuralOutput || filetype == OUTPUT)
        {
            cout << " |--> Neural Output: ";
            dataSet[i]->printNeuralOutput();
            cout << endl;
        }
    }

    cout << endl << "#======================================================#" << endl << endl;
}

